//
//@author jltxseo
// Created by junlintianxia on 2018/8/2.
//
#include "util/GLUtils.h"
#include "util/XqLog.h"
#include "../../util/Shader.h"
#include "../shaders/shaderR.h"
#include "TutorialLessonThree.h"

#define  LOG_TAG    "TutorialLessonThree"

TutorialLessonThree::TutorialLessonThree() {

}

TutorialLessonThree::~TutorialLessonThree() {

}

void TutorialLessonThree::create() {
    TutorialLesson::create();
    mShader = new Shader(lessonThreeVertexShader, lessonThreeFragmentShader);
    mPointShader = new Shader(lessonThreePointVertexShader, lessonThreePointFragmentShader);
    if (!mShader->programID || !mPointShader->programID) {
        LOGD(LOG_TAG, "Could not create program");
        return;
    }

    mModelMatrix = new Matrix();
    mMVPMatrix = new Matrix();

    // Position the eye in front of the origin.
    float eyeX = 0.0f;
    float eyeY = 0.0f;
    float eyeZ = 1.5f;

    // We are looking at the origin
    float centerX = 0.0f;
    float centerY = 0.0f;
    float centerZ = 0.0f;

    // Set our up vector.
    float upX = 0.0f;
    float upY = 1.0f;
    float upZ = 0.0f;

    // Set the view matrix.
    mViewMatrix = Matrix::newLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);

}

void TutorialLessonThree::change(int width, int height) {
    TutorialLesson::change(width, height);

    // Create a new perspective projection matrix. The height will stay the same
    // while the width will vary as per aspect ratio.
    float ratio = (float) width / height;
    float left = -ratio;
    float right = ratio;
    float bottom = -1.0f;
    float top = 1.0f;
    float near = 1.0f;
    float far = 2.0f;

    mProjectionMatrix = Matrix::newFrustum(left, right, bottom, top, near, far);

}

void TutorialLessonThree::draw() {
    TutorialLesson::draw();
    if (mShader->programID > 0) {
        mShader->use();
        long time = GLUtils::currentTimeMillis() % 10000L;
        float angleInDegrees = (360.0f / 10000.0f) * ((int) time);
        // Draw the triangle facing straight on.
        mModelMatrix->identity();
        mModelMatrix->rotate(angleInDegrees, 0.0f, 0.0f, 1.0f);

        drawTriangle();

        // Draw one translated a bit down and rotated to be flat on the ground.
        mModelMatrix->identity();
        mModelMatrix->translate(0.0f, -1.0f, 0.0f);
        mModelMatrix->rotate(90.0f, 1.0f, 0.0f, 0.0f);
        mModelMatrix->rotate(angleInDegrees, 0.0f, 0.0f, 1.0f);
        drawTriangle();

    } else {
        LOGE(LOG_TAG, "Failed to create program");
    }

    if (mPointShader->programID > 0) {
        mPointShader->use();
        drawPoint();
    } else {
        LOGE(LOG_TAG, "Failed to create point program");
    }
}

void TutorialLessonThree::drawTriangle() {
    //三角形设置程序中顶点位置属性
    mShader->setVertexAttribPointer("a_Position",
                                    3,                  // size  每个顶点属性的数据个数。可能的取值是1、2、3或者4.初始值是4
                                    GL_FLOAT,           // type 数组中每个数据的类型。可能的取值是：GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT, or GL_DOUBLE。初始值是GL_FLOAT。
                                    GL_FALSE,           // normalized?  指定顶点数在被访问的时候是否需要被归一化。
                                    4 * 7,                  // stride  两个连续顶点的属性之间的偏移量。7个数据为一组，每个数据浮点数占4
                                    triangle1VerticesData            // array buffer offset 指向数组中的第一个顶点属性的第一个数据。
    );

    //三角形设置程序中颜色属性
    mShader->setVertexAttribPointer("a_Color",
                                    4,
                                    GL_FLOAT,
                                    GL_FALSE,
                                    4 * 7,
                                    triangle1VerticesData + 3
    );
    // model * view
    mMVPMatrix->multiply(*mViewMatrix, *mModelMatrix);

    // model * view * projection
    mMVPMatrix->multiply(*mProjectionMatrix, *mMVPMatrix);

    //一旦我们有常量地址以及它的类型和矩阵尺寸，我们可以使用数值装载常量
    mShader->setUniformMatrix4fv("u_MVPMatrix", 1, GL_FALSE, mMVPMatrix->mData);

    //绘制三角形
    glDrawArrays(GL_TRIANGLES, 0, 3); // Starting from vertex 0; 3 vertices total -> 1 triangle
}

void TutorialLessonThree::drawPoint() {
    //绘制点设置顶点位置属性
    mPointShader->setVertexAttribPointer("a_Position",
                                         3,                  // size  每个顶点属性的数据个数。可能的取值是1、2、3或者4.初始值是4
                                         GL_FLOAT,           // type 数组中每个数据的类型。可能的取值是：GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT, or GL_DOUBLE。初始值是GL_FLOAT。
                                         GL_FALSE,           // normalized?  指定顶点数在被访问的时候是否需要被归一化。
                                         4 * 7,                  // stride  两个连续顶点的属性之间的偏移量。7个数据为一组，每个数据浮点数占4
                                         pointVerticesData            // array buffer offset 指向数组中的第一个顶点属性的第一个数据。
    );

    //绘制点设置程序中颜色属性
    mPointShader->setVertexAttribPointer("a_Color",
                                         4,
                                         GL_FLOAT,
                                         GL_FALSE,
                                         4 * 7,
                                         pointVerticesData + 3
    );

    //一个使用我们传入的顶点信息，在绘制buffer中真正进行绘制的API,绘制点
    glDrawArrays(GL_POINTS, 0, 1);
}


